﻿using UnityEngine;
using System.Collections.Generic;
using System;

namespace ProjectTW.Foliage
{
    public static class FoliageMapUtility
    {
        // 区域颜色缓存池
        private static Dictionary<int, Color32[]> s_BlockColorCache = new Dictionary<int, Color32[]>();

        /// <summary>
        /// 生成细节对象密度图
        /// </summary>
        /// <param name="prototypeIndex"></param>
        /// <param name="foliageInstance"></param>
        /// <returns></returns>
        public static Texture2D GenerateDensityMap(FoliageChunk foliageInstance)
        {
            int size = foliageInstance.AttachedFoliageInstance.FoliageAreaResolutionIntegral;

            Texture2D map;

            try
            {
                map = new Texture2D(size, size, TextureFormat.RGBA32, false, true)
                {
                    filterMode = FilterMode.Point, name = "Density Map Texture_Chunk: " + foliageInstance.AttachedFoliageInstance.Pos
                };
            }
            catch (Exception ex)
            {
                throw new FoliageException();
            }

#if UNITY_EDITOR
            if (!Application.isPlaying)
            {
                UnityEditor.EditorUtility.SetDirty(foliageInstance);
                UnityEditor.SceneManagement.EditorSceneManager.MarkAllScenesDirty();
            }
#endif
            return map;
        }

        /// <summary>
        /// 创建草图
        /// </summary>
        /// <param name="foliageInstance"></param>
        /// <returns></returns>
        public static FoliageDensityMap CreateDensityMap(FoliageChunk foliageInstance)
        {
            int size = foliageInstance.AttachedFoliageInstance.FoliageAreaResolutionIntegral;
            FoliageDensityMap densityMap = new FoliageDensityMap(GenerateDensityMap(foliageInstance), PoolColors(size), foliageInstance);

            return densityMap;
        }

        /// <summary>
        /// 获取颜色图路径
        /// </summary>
        /// <param name="foliageInstance"></param>
        /// <returns></returns>
        public static string GetColorMapPath(FoliageInstanceObject foliageInstance)
        {
            return GetMapPath("Color", foliageInstance.Guid, "");
        }

        /// <summary>
        /// 释放图
        /// </summary>
        /// <param name="map"></param>
        /// <param name="path"></param>
        public static void DisposeMap(Texture2D map, string path)
        {
            if (map != null)
            {
                UnityEngine.Object.DestroyImmediate(map);
            }
        }

        /// <summary>
        /// 保存草图
        /// </summary>
        /// <param name="foliageInstance"></param>
        public static void SaveDensityMaps(FoliageInstanceObject foliageInstance)
        {
            foliageInstance.DensityMap.Save();
        }

        /// <summary>
        /// 生成世界图，包含高度图信息
        /// </summary>
        /// <param name="foliageInstance"></param>
        /// <param name="updateHeights"></param>
        /// <returns></returns>
        /// <exception cref="Exception"></exception>
        public static FoliageWorldMaps GenerateWorldMaps(FoliageChunk foliageInstance, bool updateHeights = true)
        {
            if (foliageInstance == null)
            {
                return null;
            }

            int mapResolution = foliageInstance.AttachedFoliageInstance.FoliageAreaResolutionIntegral;

            FoliageWorldMaps worldsInformation;

            try
            {
                Texture2D heightMapTexture = new Texture2D(mapResolution, mapResolution, TextureFormat.RGB24, false, true)
                {
                    filterMode = FilterMode.Point, name = "Height Map Texture_Chunk: " + foliageInstance.AttachedFoliageInstance.Pos
                };

                worldsInformation = new FoliageWorldMaps(heightMapTexture, foliageInstance, updateHeights);
            }
            catch (Exception ex)
            {
                throw ex;
            }

#if UNITY_EDITOR
            if (!Application.isPlaying)
            {
                UnityEditor.EditorUtility.SetDirty(foliageInstance);
                UnityEditor.SceneManagement.EditorSceneManager.MarkAllScenesDirty();
            }
#endif
            return worldsInformation;
        }

        public static Color32[] PoolColors(int mapResolution)
        {
            Color32[] cache;

            if (!s_BlockColorCache.TryGetValue(mapResolution, out cache))
            {
                cache = new Color32[mapResolution * mapResolution];

                s_BlockColorCache.Add(mapResolution, cache);
            }

            return cache;
        }

        public static void SaveMap(FoliageMapBase mapBase, string path)
        {
            //CreateAndSaveTexture(path, map.EncodeToPNG(), map.mapWidth, map.map.format);
        }

        public static bool GetMapHit(Ray ray, out RaycastHit hit, float maxDistance)
        {
            RaycastHit[] hits = Physics.RaycastAll(ray, maxDistance, FoliageManager.Instance.FoliageGenerationLayerMask);

            System.Array.Sort<RaycastHit>(hits, delegate(RaycastHit a, RaycastHit b)
            {
                return a.distance.CompareTo(b.distance);
            });

            bool lengthBiggerThan0 = hits.Length > 0;

            hit = lengthBiggerThan0 ? hits[0] : new RaycastHit();

            return lengthBiggerThan0;
        }

        /// <summary>
        /// Get a hit for the maps (included with the map mask which is specified on the Foliage manager)
        /// </summary>
        /// <param name="ray"></param>
        /// <param name="maxDistance"></param>
        /// <returns></returns>
        public static bool GetMapHit(Vector3 origin, Vector3 direction, out RaycastHit hit, float maxDistance)
        {
            return GetMapHit(new Ray(origin, direction), out hit, maxDistance);
        }

        private static RaycastHit tempHit;

        /// <summary>
        /// Get a hit for the maps (included with the map mask which is specified on the Foliage manager)
        /// </summary>
        /// <param name="ray"></param>
        /// <param name="maxDistance"></param>
        /// <returns></returns>
        public static float GetHeightFast(Vector3 origin, Vector3 direction, int layerMask)
        {
            Physics.Raycast(origin, direction, out tempHit, Mathf.Infinity, layerMask);

            return tempHit.point.y;
        }

        /// <summary>
        /// Create and save a map texture.
        /// </summary>
        /// <param name="path"></param>
        /// <param name="bytes"></param>
        public static void CreateAndSaveTexture(string resourcesPath, byte[] bytes, int size, TextureFormat textureFormat)
        {
        }

        /// <summary>
        /// 获取图的路径
        /// </summary>
        /// <param name="mapName"></param>
        /// <param name="guid"></param>
        /// <param name="identifier"></param>
        public static string GetMapPath(string mapName, string guid, string identifier)
        {
            return string.Format("Maps/{0}_{1}_{2}", mapName, guid, identifier);
        }
    }
}
